package xyz.penghaonan.wificonnect.sockethelper;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import com.penghaonan.appframework.utils.Logger;
import com.penghaonan.appframework.utils.WeakObservableList;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

import xyz.penghaonan.wificonnect.WifiConnectSDK;
import xyz.penghaonan.wificonnect.message.BaseResponseMsg;
import xyz.penghaonan.wificonnect.message.IMsg;
import xyz.penghaonan.wificonnect.message.MsgReceiver;
import xyz.penghaonan.wificonnect.message.MsgSender;

public abstract class BaseSocketHelper {
    protected static final int SERVER_PORT = 65432;

    protected InputStream inputStream = null;
    protected OutputStream outputStream = null;

    public interface OnReceiveListener {
        void onReceived(String text);
    }

    private final WeakObservableList<OnReceiveListener> listenerList = new WeakObservableList<>();
    private boolean isReleased;

    public interface DeviceConnectListener {
        int STATE_DISCONNECT = 1;
        int STATE_CONNECTED = 2;
        int STATE_WAITING = 3;

        void onDeviceConnectStateChanged(int state);
    }

    protected final WeakObservableList<DeviceConnectListener> connectObserver = new WeakObservableList<>();

    public BaseSocketHelper() {
        addReceiveListener(new MsgReceiver() {
            @Override
            protected void onMsgReceived(IMsg msg) {
                if (msg == null) {
                    return;
                }
                Logger.i("message > receive:" + msg.getClass().getSimpleName() + "(" + msg.getSessionId() + ")");
                if (msg instanceof BaseResponseMsg) {
                    MsgSender.onResponse((BaseResponseMsg) msg);
                }
                WifiConnectSDK.Config config = WifiConnectSDK.getConfig();
                if (config != null) {
                    config.OnMsgReceived(msg);
                }
            }
        });
    }

    public void addReceiveListener(OnReceiveListener listener) {
        listenerList.addListener(listener);
    }

    public void removeReceiveListener(OnReceiveListener listener) {
        listenerList.removeListener(listener);
    }

    public void addDeviceConnectListener(DeviceConnectListener listener) {
        connectObserver.addListener(listener);
    }

    public void removeDeviceConnectListener(DeviceConnectListener listener) {
        connectObserver.removeListener(listener);
    }

    public boolean isConnected() {
        return outputStream != null && inputStream != null;
    }

    protected void notifyConnectState(int state) {
        connectObserver.iterate(new WeakObservableList.OnIterator<DeviceConnectListener>() {
            @Override
            protected boolean onIterator(DeviceConnectListener item) {
                item.onDeviceConnectStateChanged(state);
                return false;
            }
        });
    }

    protected void postToUI(String text) {
        Message message = Message.obtain(handler);
        try {
            message.obj = URLDecoder.decode(text, "utf-8");
            message.sendToTarget();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    private Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(final Message msg) {
            super.handleMessage(msg);
            if (msg.obj == null || listenerList.observerCount() == 0) {
                return;
            }
            listenerList.iterate(new WeakObservableList.OnIterator<OnReceiveListener>() {
                @Override
                protected boolean onIterator(OnReceiveListener item) {
                    item.onReceived(msg.obj.toString());
                    return false;
                }
            });
        }
    };

    public void release() {
        notifyConnectState(DeviceConnectListener.STATE_DISCONNECT);
        isReleased = true;
        if (handler != null) {
            handler.removeCallbacksAndMessages(null);
            handler = null;
        }
        listenerList.clear();
    }

    public boolean isReleased() {
        return isReleased;
    }

    abstract public boolean send(String text);
}
